// SPDX-License-Identifier: GPL-2.0+
/*
 * Created by xiaoqzye@qq.com
 *
 * Architectural registers dump
 *
 * 2020/10/24
 */

#include <common.h>
#include <command.h>
#include <vsprintf.h>

extern uint32_t mips_dump_cp0(uint32_t regNum,
	uint32_t selector, uint32_t * pvals);
extern uint64_t mips_read_cp0(uint32_t regNum,
	uint32_t selector);

static int do_dump_cp0(struct cmd_tbl * cmd,
	int flags, int argc, char * const argv[])
{
	int idx;

	if (argc <= 0x1 || (argc & 0x1) == 0)
		return CMD_RET_USAGE;
	for (idx = 1; idx < argc; idx += 0x2) {
		char * retstr;
		uint32_t regnum, selector;
		uint32_t regval, retvals[2];

		retstr = NULL;
		regnum = (uint32_t) simple_strtoul(argv[idx], &retstr, 0);
		if (regnum >= 0x20 || retstr == argv[idx]) {
			fprintf(stderr, "Error, invalid CP0 register: %s\n", argv[idx]);
			return CMD_RET_FAILURE;
		}

		retstr = NULL;
		selector = (uint32_t) simple_strtoul(argv[idx + 1], &retstr, 0);
		if (selector >= 0x8 || retstr == argv[idx + 1]) {
			fprintf(stderr, "Error, invalid CP0 selector: %s\n", argv[idx + 1]);
			return CMD_RET_FAILURE;
		}

		retvals[0] = retvals[1] = 0;
		regval = mips_dump_cp0(regnum, selector, retvals);
		fprintf(stdout, "MIPS/CP0[%02u, %u]:         0x%08x\n",
			regnum, selector, regval);

		fprintf(stdout, "\t[0x%08x]: 0x%08x <=> 0x%08x\n",
			retvals[0], retvals[1], *((uint32_t *)((unsigned long) retvals[0])));
	}
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(dumpcp0, 9, 1, do_dump_cp0,
	"Dump registers from coprocessor 0 for MIPS",
	"register0 selector0 [register1 selector1] ...");

static int do_read_cp0(struct cmd_tbl *cmd,
	int flags, int argc, char *const argv[])
{
	int idx;

	if (argc <= 0x1 || (argc & 0x1) == 0)
		return CMD_RET_USAGE;
	for (idx = 1; idx < argc; idx += 0x2) {
		char * retstr;
		uint64_t regval;
		uint32_t regnum, selector;

		retstr = NULL;
		regnum = (uint32_t) simple_strtoul(argv[idx], &retstr, 0);
		if (regnum >= 0x20 || retstr == argv[idx]) {
			fprintf(stderr, "Error, invalid CP0 register: %s\n", argv[idx]);
			return CMD_RET_FAILURE;
		}

		retstr = NULL;
		selector = (uint32_t) simple_strtoul(argv[idx + 1], &retstr, 0);
		if (selector >= 0x8 || retstr == argv[idx + 1]) {
			fprintf(stderr, "Error, invalid CP0 selector: %s\n", argv[idx + 1]);
			return CMD_RET_FAILURE;
		}

		regval = mips_read_cp0(regnum, selector);
		if ((regval >> 32) != 0) {
			fprintf(stderr, "Error, failed to read MIPS/CP0[%02u, %u]\n",
				regnum, selector);
			return CMD_RET_FAILURE;
		}
		fprintf(stdout, "MIPS/CP0[%02u, %u]:         0x%08x\n",
			regnum, selector, (uint32_t) regval);
	}
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(readcp0, 9, 1, do_read_cp0,
	"Read registers from coprocessor 0 for MIPS",
	"register0 selector0 [register1 selector1] ...");
